home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-12-19 | 13.8 KB | 504 lines | [TEXT/CWIE] |
- // =================================================================================
- //
- // CClockControl.cpp ©1996 Microsoft Corporation All rights reserved.
- //
- // =================================================================================
-
- #include "ocheaders.h"
- #include <math.h>
- #include "CClockControl.h"
-
-
- const Uint16 Shades[2][7] = { /* not pressed */ 0xf000, 0xd000, 0xc000, 0x8800, 0x7000, 0x5000, 0x3000,
- /* pressed */ 0xd000, 0xb000, 0x9000, 0x7000, 0x6000, 0x4000, 0x2000 };
- const Int16 ShinySpot = -45;
- const Int16 Face_Shade = 3;
- const Int16 HighKey_Shade = 0;
- const Int16 HiMedKey_Shade = 1;
- const Int16 MedHiKey_Shade = 2;
- const Int16 MedKey_Shade = 3;
- const Int16 MedLowKey_Shade = 4;
- const Int16 LowMedKey_Shade = 5;
- const Int16 LowKey_Shade = 6;
-
- const Int32 DefaultIdleTicks = 60;
- const Uint32 DefaultIdleRefCon = 0;
-
-
- #pragma mark === CClockControl::Construction & Destruction ===
-
-
- //=--------------------------------------------------------------------------=
- // CClockControl::CClockControl
- //=--------------------------------------------------------------------------=
-
- CClockControl::CClockControl(void)
- {
- ::GetTime(&mTime);
- mEraseTime = mTime;
- mHandsDirty = 1;
- mFaceDirty = 1;
- mIsPressed = false;
- mIsIdling = false;
- }
-
-
- //=--------------------------------------------------------------------------=
- // CClockControl::~CClockControl
- //=--------------------------------------------------------------------------=
-
- CClockControl::~CClockControl()
- {
- }
-
- #pragma mark === CClockControl::IControl Interface ===
-
-
- //=--------------------------------------------------------------------------=
- // CClockControl::IControl::Draw
- //=--------------------------------------------------------------------------=
-
- STDMETHODIMP
- CClockControl::Draw( DrawContext* inContext)
- {
- if (inContext->DrawAspect != DVASPECT_CONTENT)
- return DV_E_DVASPECT;
-
- // we are in a context aspect, be sure we are idling
- StartIdling();
-
- mFaceDirty = 1; // if we are called to draw from outside then assume we'd better do the whole thing
- DrawMe(&inContext->Location, 1);
-
- return S_OK;
- }
-
-
- //=--------------------------------------------------------------------------=
- // CClockControl::IControl::DoMouse
- //=--------------------------------------------------------------------------=
-
- STDMETHODIMP
- CClockControl::DoMouse(MouseEventType inMouseET, PlatformEvent* inEvent)
- {
- #pragma unused (inEvent)
- ErrorCode theResult = S_FALSE;
-
- switch (inMouseET)
- {
- case MouseUp:
- mIsPressed = false;
- mFaceDirty = 1;
- DrawAllContexts();
- theResult = S_OK;
- break;
-
- case MouseDown:
- mIsPressed = true;
- mFaceDirty = 1;
- DrawAllContexts();
- theResult = S_OK;
- break;
-
- case MouseEnter:
- InitCursor(); // We'll use the arrow cursor for now.
- break;
- }
-
- return theResult;
- }
-
-
- //=--------------------------------------------------------------------------=
- // CClockControl::IControl::DoIdle
- //=--------------------------------------------------------------------------=
-
- STDMETHODIMP
- CClockControl::DoIdle(Uint32 IdleRefCon)
- {
- #pragma unused(IdleRefCon)
-
- DateTimeRec NewTime;
-
- ::GetTime(&NewTime);
- mHandsDirty = (NewTime.second != mTime.second || NewTime.minute != mTime.minute
- || NewTime.hour != mTime.hour) ? 1 : 0;
- if (mHandsDirty)
- {
- mTime = NewTime;
- DrawAllContexts();
- mContainerSiteP->OnChange(ViewChange);
- }
-
- return S_OK;
- }
-
-
- #pragma mark === CClockControl::protected methods ===
-
- //=--------------------------------------------------------------------------=
- // CClockControl::StartIdling
- //=--------------------------------------------------------------------------=
-
- Boolean8
- CClockControl::StartIdling(void)
- {
- if (!mIsIdling)
- mIsIdling = mContainerSiteP->SetIdleTime(DefaultIdleTicks, DefaultIdleRefCon) == S_OK;
-
- return mIsIdling;
- }
-
-
- //=--------------------------------------------------------------------------=
- // CClockControl::StopIdling
- //=--------------------------------------------------------------------------=
-
- Boolean8
- CClockControl::StopIdling(void)
- {
- if (mIsIdling && mContainerSiteP->SetIdleTime(RemoveAllIdlers, NULL) == S_OK)
- mIsIdling = false;
-
- return !mIsIdling;
- }
-
-
- #pragma mark === CClockControl::private methods ===
-
- //=--------------------------------------------------------------------------=
- // CClockControl::DrawAllContexts
- //=--------------------------------------------------------------------------=
-
- void
- CClockControl::DrawAllContexts()
- {
- Boolean8 ShouldBeIdling = false;
- Int32 Index = 1;
- DrawContext Context = {BeginPortType};
- UInt32 ContextID;
-
- while ( GetContextID(Index, &ContextID) )
- {
- if (mContainerSiteP->AcquireContext(ContextID, &Context) == S_OK)
- {
- // we could do this by watching context changes, but this is a simple
- // control which ignores such things - so instead we'll just watch this way
- if (Context.DrawAspect == DVASPECT_CONTENT)
- ShouldBeIdling = true;
- DrawMe(&Context.Location, Index);
- mContainerSiteP->ReleaseContext(&Context);
- }
- ++Index;
- }
-
- if (ShouldBeIdling != mIsIdling)
- {
- if (ShouldBeIdling)
- StartIdling();
- else
- StopIdling();
- }
-
- mEraseTime = mTime;
- }
-
-
- //=--------------------------------------------------------------------------=
- // CClockControl::DrawMe
- //=--------------------------------------------------------------------------=
-
- void
- CClockControl::DrawMe(Rect *BoundsRect, Int32 ContextIndex)
- {
- Int16 Pressed;
- Rect OuterRimRect;
- Rect InnerRimRect;
- RGBColor col = { 0 };
- Uint16 height, width;
-
- Int16 ShinyArcAngle = 15;
- const Int16 PressDistance = 2;
- const Int16 BorderThickness = 3;
- const Int16 RimThickness = 6;
-
-
- // figure the bounding rectangles
- ::SetRect(&OuterRimRect, BoundsRect->left, BoundsRect->top, BoundsRect->right, BoundsRect->bottom);
- if (mIsPressed)
- {
- Pressed = 1;
- OuterRimRect.top += PressDistance;
- OuterRimRect.left += PressDistance;
- }
- else
- {
- Pressed = 0;
- OuterRimRect.bottom -= PressDistance;
- OuterRimRect.right -= PressDistance;
- }
- InnerRimRect = OuterRimRect;
- ::InsetRect(&InnerRimRect, RimThickness, RimThickness);
-
- if (mFaceDirty == ContextIndex)
- {
- // clear the whole clock area
- col.red = col.green = col.blue = Shades[1][Face_Shade];
- ::RGBForeColor(&col);
- {
- Rect TempRect;
- Int16 Press;
-
- if (Pressed)
- Press = -PressDistance;
- else
- Press = PressDistance;
-
- TempRect = OuterRimRect;
- ::OffsetRect(&TempRect, Press, Press);
- ::PaintOval(&TempRect);
- }
- ::PaintOval(&OuterRimRect);
-
- col.red = col.green = col.blue = Shades[Pressed][Face_Shade];
- ::RGBForeColor(&col);
- ::PaintOval(&OuterRimRect);
-
- // draw the raised rim
- ::PenSize(RimThickness, RimThickness);
- col.red = col.green = col.blue = Shades[Pressed][Face_Shade] + 0x1000;
- ::RGBForeColor(&col);
- ::FrameOval(&OuterRimRect);
-
- // figure out where the specular reflection falls
- height = OuterRimRect.bottom - OuterRimRect.top;
- width = OuterRimRect.right - OuterRimRect.left;
- if (height > width)
- ShinyArcAngle += Uint16((height - width) * 20.0 / height);
- else
- ShinyArcAngle += Uint16((width - height) * 20.0 / width);
-
- // draw the frame
- ::PenSize(BorderThickness, BorderThickness);
- col.red = col.green = col.blue = Shades[Pressed][HighKey_Shade];
- ::RGBForeColor(&col);
- ::FrameArc(&OuterRimRect, ShinySpot - ShinyArcAngle, ShinyArcAngle * 2);
- ::FrameArc(&InnerRimRect, 180 + ShinySpot - ShinyArcAngle, ShinyArcAngle * 2);
-
- col.red = col.green = col.blue = Shades[Pressed][HiMedKey_Shade];
- ::RGBForeColor(&col);
- ::FrameArc(&OuterRimRect, ShinySpot + ShinyArcAngle, 65 - ShinyArcAngle);
- ::FrameArc(&OuterRimRect, ShinySpot - ShinyArcAngle, ShinyArcAngle - 65);
- ::FrameArc(&InnerRimRect, 180 + ShinySpot + ShinyArcAngle, 65 - ShinyArcAngle);
- ::FrameArc(&InnerRimRect, 180 + ShinySpot - ShinyArcAngle, ShinyArcAngle - 65);
-
- col.red = col.green = col.blue = Shades[Pressed][MedHiKey_Shade];
- ::RGBForeColor(&col);
- ::FrameArc(&OuterRimRect, ShinySpot + 65, 20);
- ::FrameArc(&OuterRimRect, ShinySpot - 65, -20);
- ::FrameArc(&InnerRimRect, 180 + ShinySpot + 65, 20);
- ::FrameArc(&InnerRimRect, 180 + ShinySpot - 65, -20);
-
- col.red = col.green = col.blue = Shades[Pressed][MedLowKey_Shade];
- ::RGBForeColor(&col);
- ::FrameArc(&OuterRimRect, 180 + ShinySpot + 65, 20);
- ::FrameArc(&OuterRimRect, 180 + ShinySpot - 65, -20);
- ::FrameArc(&InnerRimRect, ShinySpot + 65, 20);
- ::FrameArc(&InnerRimRect, ShinySpot - 65, -20);
-
- col.red = col.green = col.blue = Shades[Pressed][LowMedKey_Shade];
- ::RGBForeColor(&col);
- ::FrameArc(&OuterRimRect, 180 + ShinySpot + ShinyArcAngle, 65 - ShinyArcAngle);
- ::FrameArc(&OuterRimRect, 180 + ShinySpot - ShinyArcAngle, ShinyArcAngle - 65);
- ::FrameArc(&InnerRimRect, ShinySpot + ShinyArcAngle, 65 - ShinyArcAngle);
- ::FrameArc(&InnerRimRect, ShinySpot - ShinyArcAngle, ShinyArcAngle - 65);
-
- col.red = col.green = col.blue = Shades[Pressed][LowKey_Shade];
- ::RGBForeColor(&col);
- ::FrameArc(&OuterRimRect, 180 + ShinySpot - ShinyArcAngle, ShinyArcAngle * 2);
- ::FrameArc(&InnerRimRect, ShinySpot - ShinyArcAngle, ShinyArcAngle * 2);
-
- mFaceDirty++;
- }
- else if (mHandsDirty == ContextIndex)
- {
- // erase the hands
- col.red = col.green = col.blue = Shades[Pressed][Face_Shade];
- DrawHands(&InnerRimRect, &mEraseTime, &col, true, Pressed);
-
- mHandsDirty++;
- }
-
- // draw the hands
- {
- col.red = col.green = col.blue = Shades[Pressed][LowKey_Shade];
- DrawHands(&InnerRimRect, &mTime, &col, false, Pressed);
- }
- }
-
-
- //=--------------------------------------------------------------------------=
- // CClockControl::DrawMe
- //=--------------------------------------------------------------------------=
-
- void
- CClockControl::DrawHands(Rect *ClockRect, DateTimeRec *Time, RGBColor *Color, Boolean8 Erasing, Int16 Pressed)
- {
- #pragma unused (Pressed)
- Int16 Angle, ShinyAngle;
- Int16 X[4];
- Int16 Y[4];
- Int16 i;
- RgnHandle HandRgn = ::NewRgn();
-
-
- ::PenSize(1, 1);
- ShinyAngle = (450 - ShinySpot) % 360;
-
- for (i = 0; i < 3; i++)
- {
- if (i == 0)
- {
- // hour hand
- Angle = (450 - (Time->hour % 12) * 30 - Time->minute / 2) % 360;
- FigureHandPoints(Angle, 0.5, 10, ClockRect, X, Y);
- }
- else if (i == 1)
- {
- // minute hand
- Angle = (450 - Time->minute * 6) % 360;
- FigureHandPoints(Angle, 0.8, 5, ClockRect, X, Y);
- }
- else if (i == 2)
- {
- // second hand - the really simple case
- Angle = (450 - Time->second * 6) % 360;
- FigureHandPoints(Angle, 0.88, 3, ClockRect, X, Y);
- }
-
- ::OpenRgn();
- ::MoveTo(X[3], Y[3]);
- ::LineTo(X[0], Y[0]);
- ::LineTo(X[1], Y[1]);
- ::LineTo(X[2], Y[2]);
- ::LineTo(X[3], Y[3]);
- ::CloseRgn(HandRgn);
- ::RGBForeColor(Color);
- ::PaintRgn(HandRgn);
- HighlightHands(ShinyAngle, Angle, Color, Erasing, X, Y);
- }
-
- ::DisposeRgn(HandRgn);
- }
-
-
- //=--------------------------------------------------------------------------=
- // CClockControl::FigureHandPoints
- //=--------------------------------------------------------------------------=
-
- void
- CClockControl::FigureHandPoints(Int16 Angle, double LengthPercent, Int16 WidthPixels, Rect *ClockRect, Int16 *XArray, Int16 *YArray)
- {
- const double DegToRad = pi / 180.0;
-
- Int16 CenterX = (Int32(ClockRect->right) + ClockRect->left) / 2;
- Int16 CenterY = (Int32(ClockRect->bottom) + ClockRect->top) / 2;
-
- double Radians;
- double Sine, Cosine;
- double AdjSine, AdjCosine;
- double XLength, YLength, Ratio, Radius;
-
- {
- Int16 height = ClockRect->bottom - ClockRect->top;
- Int16 width = ClockRect->right - ClockRect->left;
- Ratio = double(height) / (width > 0 ? width : 1);
- Radius = width / 2;
- }
-
- Radians = Angle * DegToRad;
- Cosine = cos(Radians);
- Sine = sin(Radians);
- AdjCosine = Cosine * WidthPixels;
- AdjSine = Sine * WidthPixels;
- XLength = Radius * LengthPercent;
- YLength = XLength * Ratio;
- XArray[3] = CenterX + XLength * Cosine;
- XArray[0] = CenterX - AdjSine;
- XArray[1] = CenterX - AdjCosine;
- XArray[2] = CenterX + AdjSine;
- YArray[3] = CenterY - YLength * Sine;
- YArray[0] = CenterY - AdjCosine;
- YArray[1] = CenterY + AdjSine;
- YArray[2] = CenterY + AdjCosine;
- }
-
-
- //=--------------------------------------------------------------------------=
- // CClockControl::Reflection
- //=--------------------------------------------------------------------------=
-
- Int16 CClockControl::Reflection(Int16 InboundLight, Int16 StartX, Int16 StartY, Int16 EndX, Int16 EndY)
- {
- const double RadToDegrees = 180.0 / pi;
- const double DegreesToRad = pi / 180.0;
- double dx, dy;
- Int16 theta, ReturnValue;
-
- dx = EndX - StartX;
- dy = StartY - EndY;
- theta = ::atan(dy/dx) * RadToDegrees;
-
- if (InboundLight > 90)
- InboundLight -= 180;
- else if (InboundLight < -90)
- InboundLight += 180;
- theta -= InboundLight;
- ReturnValue = (::sin(theta * DegreesToRad)) * 256;
- if (ReturnValue < 0)
- ReturnValue *= -1;
-
- return ReturnValue;
- }
-
-
- //=--------------------------------------------------------------------------=
- // CClockControl::HighlightHands
- //=--------------------------------------------------------------------------=
-
- void
- CClockControl::HighlightHands(Int16 LightAngle, Int16 HandAngle, RGBColor *Color, Boolean Erasing, Int16 *XArray, Int16 *YArray)
- {
- Int16 i, j, DeltaAngle = (360 + LightAngle - HandAngle) % 360;
-
- ::RGBForeColor(Color);
- ::MoveTo(XArray[3], YArray[3]);
- for (i = 0, j = 3; i < 4; j = i, i++)
- {
- if (!Erasing)
- {
- Boolean Eclipsed = false;
- Int32 Brightness = Reflection(LightAngle, XArray[j], YArray[j], XArray[i], YArray[i]);
- RGBColor EdgeColor;
-
- if (i == 0 && (DeltaAngle > 175 && DeltaAngle < 355))
- Eclipsed = true;
- else if (i == 1 && (DeltaAngle > 225 || DeltaAngle < 45))
- Eclipsed = true;
- else if (i == 2 && (DeltaAngle > 315 || DeltaAngle < 135))
- Eclipsed = true;
- else if (i == 3 && (DeltaAngle > 5 && DeltaAngle < 185))
- Eclipsed = true;
-
- if (Eclipsed)
- Brightness = -Brightness;
-
- EdgeColor.red = EdgeColor.blue = EdgeColor.green = 0x8000 + (127L * Brightness);
- ::RGBForeColor(&EdgeColor);
- }
-
- ::LineTo(XArray[i], YArray[i]);
- }
- }
-
-